<?php

include_once ("Server.php");
include_once ("config.php");

abstract class BaseRepo
{
	private $BaseEntity;
	private $TableName;
	private $EntityList;
	
	abstract protected function getEntityName();
	
	public function __construct() {
		$this->BaseEntity = $this->getEntityName();
		$this->EntityList = array();
		$this->TableName = $this->BaseEntity;
	}
	
	/********************
	Public Functions
	*********************/
	
	public function get($input='') {
		if (is_numeric($input)){
			$retArray = $this->_getFromArray(array($input));
			return $retArray[0];
		} elseif(is_array($input)){
			return $this->_getFromArray($input);
		} else {
			$ids = $this->_selectIDs($input);
			if (empty($ids)) return false;
			return $this->_getFromArray($ids);
		}				
	}
	
	public function add($entity){
		if (is_array($entity)){
			$entity = new $this->BaseEntity($entity);
		}
		$entity->setStatus('add');
		if (empty($this->EntityList)){
			$min_key = -1;
		} else {
			$min_key = min(array_keys($this->EntityList));
		}
		$entity->id = $min_key-1; 
		$this->EntityList[$entity->id] = $entity;
	}
	
	public function delete($entityId){
		$entity = $this->get($entityId);
		$entity->setStatus('delete');
	}
	
	public function commit() {
		$query = '';
		foreach($this->EntityList as $entity){
			switch ($entity->Status){
				case 'delete':
					$query = $query.'DELETE FROM '.$this->TableName.' WHERE id='.$entity->id.'  ';
					unset($EntityList[$entity->id]);
					break;
				case 'edit':
					$query = $query.$this->_onEdit($entity);
					break;
				case 'add':
					$query = $query.$this->_onAdd($entity);
					unset($EntityList[$entity->id]);
					break;
				case 'remove':
					unset($EntityList[$entity->id]);
					break;
			}	
		}
		$con = connect();
		$success = query($query, $con);
		disconnect($con);
		if ($success){
			unset($EntityList[-1]);
		} else {
			trigger_error(
				'Failed to save object '.$this->BaseEntity.' of ID \''.$entity->id.'\' to the database ' .
				' in ' . $trace[0]['file'] .
				' on line ' . $trace[0]['line'],
				E_USER_NOTICE);
		}
	}
	
	/****************
	Private Functions for get()
	****************/
	
	
	private function _getFromArray($ids){
		$this->_addToList($ids);
		$retArray = array();
		foreach($ids as $id){
			$retArray[] = $this->EntityList[$id];
		}
		return $retArray;
	}
	
	private function _addToList($ids){
		$idsToGetFromDB = array_diff($ids,array_keys($this->EntityList));
		if (count($idsToGetFromDB) > 0) {
			$success = $this->_getFromDB($idsToGetFromDB);
			if(!$success){
				$trace = debug_backtrace();
				trigger_error(
					'No '.$this->BaseEntity.' Object of ID \''.$entityId.'\' exists ' .
					' in ' . $trace[0]['file'] .
					' on line ' . $trace[0]['line'],
					E_USER_NOTICE);
				return null;
			}
		}
		return null;
	}
	
	private function _selectIDs($whereClause){
		$ids = array();
		$con = connect();
		$query = "SELECT id FROM ".$this->TableName." x ".$whereClause;
		//print $query;
		$dataSet = query($query, $con);
		$rows = mysql_num_rows($dataSet);
		if ($rows == 0){
			disconnect($con);
			return $ids;
		}
		for($i=0;$i<$rows;$i++){
			$dataRow =  mysql_fetch_array($dataSet);
			$ids[] = $dataRow[id];
		}
		
		disconnect($con);
		return $ids;
	}
	
	private function _getFromDB($ids) {
		$con = connect();
		$query = "SELECT * FROM ".$this->TableName." ";
		$query = $query . "WHERE id in (";
		$numItems = count($ids);
		$i = 0;
		foreach($ids as $id){
			$query = $query.$id;
			if(++$i != $numItems){
				$query = $query.",";
			}
		}
		$query = $query . ")";
		$dataSet = query($query, $con);
		
		$rows = mysql_num_rows($dataSet);
		if ($rows == 0){
			disconnect($con);
			return false;
		}
		for($i=0;$i<$rows;++$i){
			$dataRow =  mysql_fetch_array($dataSet);
			$entity = $this->_tieToRepo($dataRow);
		}
		disconnect($con);
		return true;
	}
	
	private function _tieToRepo($dataRow){
		$newEntity = new $this->BaseEntity($dataRow);
		$this->EntityList[$newEntity->id] = $newEntity;
		return $newEntity;
	}
	
	/****************
	Private functions for commit()
	*****************/
	
	private function _onEdit($entity){
		$query = 'UPDATE '.$this->TableName.' SET ';
		//TODO: Allow for mapping
		foreach($entity->Data as $colName => $value) {
			if ($colName == 'id') continue;
			if (is_numeric($value)){
				$query = $query.$colName.'='.$value.',';
			} else {
				$query = $query.$colName.'=\''.$value.'\',';
			}
		}
		$query = substr_replace($query,' ',-1);
		$query = $query.'   ';
		return $query;
	}
	
	private function _onAdd($entity){
		$query = 'INSERT INTO '.$this->TableName.' ';
		$columns = '(';
		$values = 'VALUES (';
		$numItems = count($entity->Data);
		$i = 0;
		foreach($entity->Data as $colName => $value){
			++$i;
			if ($colName == 'id') continue;
			$columns = $columns.$colName;
			$values = $values.'\''.$value.'\'';
			end($entity->Data);
			if ($i != $numItems){
				$columns = $columns.',';
				$values = ''.$values.',';
			} else {
				$columns = $columns.')';
				$values = ''.$values.')';
			}
		}
		$query = $query.$columns.' '.$values.'  ';
		return $query;
	}
	
}


?>